﻿using BCCommon;
using BCCommon.Enums;
using BCData.Trading.SaleContract;
using BCDto.Trading.SaleContract;
using BCEntity.Trading.SaleContract;
using BCEntity.Common.EntityNameConst;
using BCService.Utils;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using BCService.Trading.SaleShoppingCart;
using BCService.Trading.SaleContractChecklist;
using BCDto.Trading.SaleContractChecklist;
using BCService.Website.UserAddress;
using BCDto.Common.Payment.PaymentRecord;
using BCCommon.TradingEnums;
using BCService.Trading.SaleContractReceiptRecord;
using BCEntity.Trading.SaleContractReceiptRecord;
using BCData.Trading.SaleContractReceiptRecord;

namespace BCService.Trading.SaleContract
{
    public class SaleContractService : ISaleContractService
    {
        private readonly IDatabaseContext databaseContext;
        private readonly IApplicationContextService applicationContextService;
        private readonly IIdGenerationService idGenerationService;
        private readonly IRedisService redisService;
        private readonly ISaleContractData saleContractData;
        private readonly ISaleShoppingCartService saleShoppingCartService;
        private readonly ISaleContractChecklistService saleContractChecklistService;
        private readonly IUserAddressService userAddressService;
        private readonly ISaleContractReceiptRecordData saleContractReceiptRecordData;
        private readonly string key = string.Format("{0}", EntityNameConst.SaleContractEntity);

        public SaleContractService(IDatabaseContext databaseContext,
            IApplicationContextService applicationContextService,
            IIdGenerationService idGenerationService,
            IRedisService redisService,
            ISaleContractData saleContractData,
            ISaleShoppingCartService saleShoppingCartService,
            ISaleContractChecklistService saleContractChecklistService,
            IUserAddressService userAddressService,
            ISaleContractReceiptRecordData saleContractReceiptRecordData)
        {
            this.databaseContext = databaseContext;
            this.applicationContextService = applicationContextService;
            this.idGenerationService = idGenerationService;
            this.redisService = redisService;
            this.saleContractData = saleContractData;
            this.saleShoppingCartService = saleShoppingCartService;
            this.saleContractChecklistService = saleContractChecklistService;
            this.userAddressService = userAddressService;
            this.saleContractReceiptRecordData = saleContractReceiptRecordData;
        }

        #region 检查销售合同是否存在
        public bool Exists(long saleContractId)
        {
            return this.saleContractData.Exists(saleContractId).GetAwaiter().GetResult();
        }
        #endregion

        #region 添加销售合同
        public SaleContractDto Add(SaleContractRequestDto requestDto)
        {
            if (!requestDto.SaleShoppingCartIds.Any())
            {
                throw new ArgumentException("未选择任何购物车中的商品,请先选择您要生成订单的商品!");
            }

            List<long> ids = new List<long>();
            foreach (long id in requestDto.SaleShoppingCartIds)
            {
                if (this.saleShoppingCartService.Exists(id))
                {
                    ids.Add(id);
                }
            }
            if (!this.userAddressService.Exists(requestDto.UserAddressId))
            {
                throw new ArgumentException("此收货地址信息不存在");
            }
            var userAddressDto = this.userAddressService.Get(requestDto.UserAddressId);

            var entity = requestDto.As<SaleContractEntity>();
            entity.UserId = applicationContextService.User.UserId;
            entity.SaleContractNo = RandomCode.GetOrderNo("BC", idGenerationService.GenerateId());
            entity.SaleAmount = this.saleShoppingCartService.SumSaleGoodsAmount(ids);
            entity.Consignee = userAddressDto.Consignee;
            entity.ConsigneePhone = userAddressDto.ConsigneePhone;
            entity.ShippingAddress = userAddressDto.Address;
            entity.ContractContent = ""; //TODO:销售合同内容

            databaseContext.BeginTransaction();
            var result = this.saleContractData.Add(entity).Result.As<SaleContractDto>();
            if (result == null)
            {
                throw new ArgumentException("生成销售订单失败!");
            }
            result.Checklist = new List<SaleContractChecklistDto>();
            foreach (long id in ids)
            {

                SaleContractChecklistRequestDto checklist = new SaleContractChecklistRequestDto
                {
                    SaleContractId = result.SaleContractId,
                    SaleContractNo = result.SaleContractNo,
                    SaleShoppingCartId = id
                };
                result.Checklist.Add(this.saleContractChecklistService.Add(checklist));
            }
            databaseContext.Commit();
            return result;
        }
        #endregion

        #region 修改销售合同
        public SaleContractDto Update(SaleContractPutDto putDto)
        {
            if (!this.Exists(putDto.SaleContractId))
            {
                throw new ArgumentException("此记录不存在!");
            }
            var entity = putDto.As<SaleContractEntity>();
            var result = this.saleContractData.Update(entity).GetAwaiter().GetResult().As<SaleContractDto>();
            string cacheKey = this.redisService.GetKey(key, entity.SaleContractId);
            this.redisService.DeleteAsync(cacheKey);
            return result;
        }
        #endregion

        #region 删除销售合同
        public bool Delete(long saleContractId)
        {
            if (!this.Exists(saleContractId))
            {
                throw new ArgumentException("此记录不存在!");
            }

            var result = this.saleContractData.Delete(saleContractId).GetAwaiter().GetResult();
            string cacheKey = this.redisService.GetKey(key, saleContractId);
            this.redisService.DeleteAsync(cacheKey);
            return result;
        }
        #endregion

        #region 获取销售合同
        public SaleContractDto Get(long saleContractId)
        {
            string cacheKey = this.redisService.GetKey(key, saleContractId);
            var result = this.redisService.TryGet(cacheKey, () =>
            {
                var data = this.saleContractData.GetEntity(saleContractId).GetAwaiter().GetResult().As<SaleContractDto>();
                data.Checklist = this.saleContractChecklistService.GetList(data.SaleContractId).ToList();
                return data;
            }, TimeSpan.FromMinutes(30));
            return result;
        }
        #endregion

        #region 获取销售合同列表
        public IEnumerable<SaleContractDto> GetList(long userId)
        {
            string cacheKey = this.redisService.GetKey(key, userId);
            var result = this.redisService.TryGet(cacheKey, () =>
            {
                var saleContractList = this.saleContractData.GetList(userId).GetAwaiter().GetResult().As<IEnumerable<SaleContractDto>>();

                foreach (var item in saleContractList)
                {
                    item.Checklist = this.saleContractChecklistService.GetList(item.SaleContractId).ToList();
                }
                return saleContractList;
            }, TimeSpan.FromMinutes(30));
            return result;
        }
        #endregion

        #region 获取销售合同分页
        public PageableList<SaleContractDto> Query(long? userId, SaleContractStatusType? saleContractStatus, DateTime? start, DateTime? end, string sortName, bool? ascending, int pageIndex, int pageSize)
        {
            string cacheKey = this.redisService.GetKey(key, userId, start, end, sortName, ascending, pageIndex, pageSize);
            var result = this.redisService.TryGet(cacheKey, () =>
            {
                var data = this.saleContractData.Query(userId, saleContractStatus, start, end, sortName, ascending, pageIndex, pageSize).GetAwaiter().GetResult();
                var list = data.Item1.As<IEnumerable<SaleContractDto>>();
                foreach (var item in list)
                {
                    item.Checklist = this.saleContractChecklistService.GetList(item.SaleContractId).ToList();
                }
                return new PageableList<SaleContractDto>
                {
                    Count = data.Item2,
                    Items = list,
                    PageIndex = pageIndex,
                    PageSize = pageSize,
                    ServerTime = DateTime.Now
                };
            }, TimeSpan.FromMinutes(30));

            return result;
        }
        #endregion

        #region 支付销售金额
        public void PaymentSaleAmount(PaymentRecordDto paymentRecordDto)
        {
            var saleContentEntity = this.saleContractData.GetEntity(long.Parse(paymentRecordDto.ReferenceNumber)).Result;
            if (saleContentEntity == null)
            {
                throw new ArgumentException("此销售合同不存在!");
            }
            databaseContext.BeginTransaction();
            if (saleContentEntity.PaymentMode == SaleContractPaymentModeType.DepositAndLastPayment)
            {
                if (!saleContentEntity.HasDepositPaid)
                {
                    saleContentEntity.DepositPaymentNo = paymentRecordDto.ReferenceNumber;
                    var result = this.saleContractData.UpdatePaymentInfoToDeposit(saleContentEntity).Result;
                    if (result == null)
                    {
                        throw new ArgumentException("修改销售合同定金支付信息失败!");
                    }
                }
                else
                {
                    saleContentEntity.LastPaymentNo = paymentRecordDto.ReferenceNumber;
                    var result = this.saleContractData.UpdatePaymentInfoToLast(saleContentEntity).Result;
                    if (result == null)
                    {
                        throw new ArgumentException("修改销售合同尾款支付信息失败!");
                    }
                }
            }
            else
            {
                saleContentEntity.FullPaymentNo = paymentRecordDto.ReferenceNumber;
                var result = this.saleContractData.UpdatePaymentInfo(saleContentEntity).Result;
                if (result == null)
                {
                    throw new ArgumentException("修改销售合同全款支付信息失败!");
                }
            }
            SaleContractReceiptRecordEntity receiptRecordEntity = new SaleContractReceiptRecordEntity()
            {
                SaleContractId = saleContentEntity.SaleContractId,
                SaleContractNo = saleContentEntity.SaleContractNo,
                PaymentTime = paymentRecordDto.SuccessTime.Value,
                PaymentAmount = paymentRecordDto.Amount,
                PaymentChannel = paymentRecordDto.PaymentChannelId.ToString(),
                PaymentRecordId = paymentRecordDto.PaymentRecordId
            };
            var receiptResult = this.saleContractReceiptRecordData.Add(receiptRecordEntity).Result;
            if (receiptResult == null)
            {
                throw new ArgumentException("追加销售合同收款记录失败!");
            }
            databaseContext.Commit();
        }
        #endregion
    }
}